package avicit.bdp.dms.prm.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.service.dto.CommonTypeDTO;
import avicit.bdp.common.service.service.CommonTypeService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.common.utils.EntityUtils;
import avicit.bdp.common.utils.enums.CommonTypeEnums;
import avicit.bdp.dds.dispatch.enums.ReleaseState;
import avicit.bdp.core.poi.util.csv.ExcelUtils;
import avicit.bdp.dms.prm.dao.DataElementDAO;
import avicit.bdp.dms.prm.dto.DataElement;
import avicit.bdp.dms.prm.dto.DataElementDTO;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.rest.msg.QueryRespBean;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.github.pagehelper.Page;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 数据元表服务
 */
@Transactional
@Service
public class DataElementService extends BaseService<DataElementDAO, DataElementDTO> {

    private static final String TYPE = "dataElement";

    @Autowired
    private CommonTypeService commonTypeService;

    /**
     * 新增数据元接口
     *
     * @return java.lang.String
     * @param    dataElement
     * @author felix
     * @date 2021/3/29 11:52
     */
    @Transactional(rollbackFor = Exception.class)
    public String insertDataElement(DataElementDTO dataElement) {
        try {
            dataElement.setId(ComUtil.getId());
            insertSelective(dataElement);
            //记录日志
            BdpLogUtil.log4Insert(dataElement);
            return dataElement.getId();
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 修改数据元接口
     *
     * @return java.lang.String
     * @param    dataElement
     * @author felix
     * @date 2021/3/29 11:52
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateDataElement(DataElementDTO dataElement) {
        try {
            updateByPrimaryKey(getDataElement(dataElement));
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    private DataElementDTO getDataElement(DataElementDTO dataElement) {
        DataElementDTO oldDTO = selectByPrimaryKey(dataElement.getId());
        if (oldDTO == null) {
            throw new BusinessException("数据不存在");
        }
        //记录日志
        BdpLogUtil.log4Update(dataElement, oldDTO);

        oldDTO.setCnName(dataElement.getCnName());
        oldDTO.setName(dataElement.getName());
        oldDTO.setCode(dataElement.getCode());
        oldDTO.setType(dataElement.getType());
        oldDTO.setLength(dataElement.getLength());
        oldDTO.setCodetable(dataElement.getCodetable());
        if (dataElement.getCodetable() != null && dataElement.getCodetable() == 1) {
            oldDTO.setCodeTableid(dataElement.getCodeTableid());
            oldDTO.setCodeColumnid(dataElement.getCodeColumnid());
        }
        oldDTO.setRemark(dataElement.getRemark());
        return oldDTO;
    }

    /**
     * 删除数据元接口
     *
     * @param    id id
     * @author felix
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteDataElement(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new BusinessException("删除失败！传入的参数主键为null");
        }
        try {
            //记录日志
            DataElementDTO dataElementDTO = selectByPrimaryKey(id);
            if (dataElementDTO == null) {
                throw new BusinessException("删除失败！对象不存在");
            }
            if (dataElementDTO.getStatus() == ReleaseState.ONLINE.getCode()) {
                throw new BusinessException("删除失败！启用状态下不可删除");
            }
            BdpLogUtil.log4Delete(dataElementDTO);
            //删除业务数据
            deleteByPrimaryKey(id);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 修改数据元状态
     *
     * @param    id
     * @author felix
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(String id, Integer status) {
        try {
            if (StringUtils.isAnyBlank(id, status.toString())) {
                throw new BusinessException("请检查参数!");
            }
            DataElementDTO dataElementDTO = new DataElementDTO();
            dataElementDTO.setId(id);
            dataElementDTO.setStatus(status);
            updateByPrimaryKeySelective(dataElementDTO);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 查询数据元列表
     *
     * @param    typeId
     * @param    keyWords
     * @param    pageNo
     * @param    pageSize
     * @author felix
     * @date 2021/3/29 13:58
     */
    @Transactional(readOnly = true)
    public QueryRespBean<DataElementDTO> getListForElement(String typeId, String keyWords, Integer pageNo, Integer pageSize) {
        QueryRespBean<DataElementDTO> queryRespBean = new QueryRespBean<>();
        try {
            List<String> typeIds = commonTypeService.getChildrenIds(CommonTypeEnums.DATA_ELEMENT, typeId, null);
            if (typeIds == null) {
                typeIds = Lists.newArrayList();
            }
            typeIds.add(typeId);
            com.github.pagehelper.PageHelper.startPage(pageNo, pageSize);
            Page<DataElementDTO> dataList = this.mapper.getList(typeIds, keyWords);
            queryRespBean.setResult(dataList);
            BdpLogUtil.log4Query(queryRespBean);
            return queryRespBean;
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 判断名称或者编码是否重复接口
     *
     * @return java.lang.Boolean
     * @param    value
     * @param    type
     * @author felix
     * @date 2021/3/30 16:02
     */
    public Boolean isSameName(String id, String value, String type) {
        Boolean flag = false;
        if (StringUtils.isAnyBlank(value, type)) {
            throw new BusinessException("请检查参数!");
        }
        DataElementDTO dataElementDTO = new DataElementDTO();
        if ("name".equals(type)) {
            dataElementDTO.setName(value);
        } else if ("code".equals(type)) {
            dataElementDTO.setCode(value);
        }
        List<DataElementDTO> list = selectList(dataElementDTO);
        if (list != null && list.size() > 0) {
            if (StringUtils.isBlank(id)) {
                return true;
            }
            for (DataElementDTO dto : list) {
                if (!dto.getId().equals(id)) {
                    flag = true;
                    break;
                }
            }
        }
        return flag;
    }

    /**
     * 查询数据元
     * @param projectId
     * @param keyWords
     * @return
     */
    public List<CommonTypeDTO> getDataElementList(String projectId, String keyWords) {
        try {
            // 顶级节点
            List<CommonTypeDTO> result = new ArrayList<>();
            // 子节点数据
            Map<String, List<CommonTypeDTO>> map = new HashMap<>();
            List<CommonTypeDTO> commonTypeList;

            // 项目空间通用树
            CommonTypeDTO commonTypeDTO = new CommonTypeDTO();
            commonTypeDTO.setType(CommonTypeEnums.DATA_ELEMENT);
            if (StringUtils.isNotEmpty(projectId)) {
                commonTypeDTO.setProjectId(projectId);
            }

            List<CommonTypeDTO> childrenType = commonTypeService.selectList(commonTypeDTO);
            commonTypeList = Stream.of(childrenType)
                    .flatMap(Collection::stream)
                    .distinct()
                    .sorted(Comparator.comparing(CommonTypeDTO::getOrderBy, Comparator.nullsLast(Integer::compareTo)))
                    .collect(Collectors.toList());

            String rootTypeId = "";
            if (CollectionUtils.isNotEmpty(commonTypeList)) {
                for (CommonTypeDTO commonType : commonTypeList) {
                    if ("-1".equals(commonType.getParentId())) {
                        result.add(commonType);
                        rootTypeId = commonType.getId();
                    } else {
                        if (map.containsKey(commonType.getParentId())) {
                            map.get(commonType.getParentId()).add(commonType);
                        } else {
                            List<CommonTypeDTO> commonTableDTOList = new ArrayList<>();
                            commonTableDTOList.add(commonType);
                            map.put(commonType.getParentId(), commonTableDTOList);
                        }
                    }
                }
            }

            List<String> typeIds = commonTypeService.getChildrenIds(CommonTypeEnums.DATA_ELEMENT, rootTypeId, projectId);
            if (typeIds == null) {
                typeIds = Lists.newArrayList();
            }
            typeIds.add(rootTypeId);
            List<DataElementDTO> dataElementList = this.mapper.getList(typeIds, keyWords);
            buildChildren(result, map, dataElementList);

            // 顶级节点不必返回
            if (result.size() == 1) {
                result = result.get(0).getChildren();
            }
            return result;
        } catch (Exception e) {
            logger.error("查询数据元异常,", e.getMessage());
            throw new BusinessException(e.getMessage(), e);
        }
    }

    private void buildChildren(List<CommonTypeDTO> list, Map<String, List<CommonTypeDTO>> map, List<DataElementDTO> dataElementList) {
        for (CommonTypeDTO commonTypeDTO : list) {
            List<CommonTypeDTO> commonTypeList = map.get(commonTypeDTO.getId());
            if (CollectionUtils.isNotEmpty(commonTypeList)) {
                buildChildren(commonTypeList, map, dataElementList);
                commonTypeDTO.setChildren(commonTypeList);
            } else {
                List<CommonTypeDTO> commonTypeDtoList = new ArrayList<>();
                // 叶子节点增加表数据到树
                if (CollectionUtils.isNotEmpty(dataElementList)) {
                    for (DataElementDTO dataElement : dataElementList) {
                        if (commonTypeDTO.getId().equals(dataElement.getTypeId())) {
                            CommonTypeDTO commonType = new CommonTypeDTO();
                            commonType.setId(dataElement.getId());
                            commonType.setName(dataElement.getName());
                            commonType.setRemark(dataElement.getCnName());
                            commonTypeDtoList.add(commonType);
                        }
                    }
                }

                commonTypeDTO.setChildren(commonTypeDtoList);
            }
        }
    }

    public void downloadTemplate(HttpServletResponse response) throws Exception {
        InputStream in = null;
        ServletOutputStream output = null;
        try {
            String fileName = "数据元.xlsx";
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resourcePatternResolver.getResources("classpath*:数据元.xlsx");
            // 如果是空的，则不执行
            if (resources.length != 0) {
                in = resources[0].getInputStream();
            }

            String downloadName = URLEncoder.encode(fileName, "UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + downloadName);
            output = response.getOutputStream();

            byte[] buffer = new byte[1024];
            int length = 0;
            while((length = in.read(buffer)) > 0){
                output.write(buffer, 0, length);
            }
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(output);
        }
    }

    public void export(String typeId, HttpServletResponse response) {
        ExcelUtils excelUtils = new ExcelUtils();

        try {
            List<Map<String, Object>> dataList = getDataList(typeId);

            List<ExcelExportEntity> entityList = new ArrayList<>();
            entityList.add(new ExcelExportEntity("中文名", "cnName", 30));
            entityList.add(new ExcelExportEntity("英文名", "name", 30));
            entityList.add(new ExcelExportEntity("编码", "code", 30));
            entityList.add(new ExcelExportEntity("数据类型", "type", 15));
            entityList.add(new ExcelExportEntity("数据长度", "length", 15));
            entityList.add(new ExcelExportEntity("状态", "status", 15));
            entityList.add(new ExcelExportEntity("备注", "remark", 40));

            String title = "数据元";
            Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(null, title), entityList, dataList);
            excelUtils.downLoadExcel(title, workbook, response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private List<Map<String, Object>> getDataList(String typeId) {
        QueryRespBean<DataElementDTO> queryRespBean = getListForElement(typeId, null, 1, Integer.MAX_VALUE);
        Page<DataElementDTO> list = queryRespBean.getResult();
        List<Map<String, Object>> dataList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for(DataElementDTO data : list){
                Map<String, Object> map = new HashMap<>();
                map.put("cnName", data.getCnName());
                map.put("name", data.getName());
                map.put("code", data.getCode());
                map.put("type", data.getType());
                map.put("length", data.getLength());
                map.put("status", data.getStatus()==1 ? "启用" : "停用");
                map.put("remark", data.getRemark());
                dataList.add(map);
            }
        }

        return dataList;
    }

    public List<DataElement> importDataElement(DataElementDTO dataElementDTO) throws Exception {
        MultipartFile file = dataElementDTO.getFile();
        CheckParaUtils.checkObjectValidity(file, logger, "参数[file]不能为空");
        CheckParaUtils.checkStringValidity(dataElementDTO.getTypeId(), logger, "分类ID不能为空");

        List<DataElement> errorList = new ArrayList<>();
        ExcelUtils excelUtils = new ExcelUtils();
        List<DataElement> dataList = excelUtils.importExcel(file, 0, 1, false, DataElement.class);
        logger.info("解析excel文件数据成功，数据有[{}]条", dataList.size());

        if (CollectionUtils.isNotEmpty(dataList)) {
            String userId = ThreadContextHelper.getUserId();
            if (StringUtils.isBlank(userId)) {
                userId = "1";
            }

            List<DataElementDTO> dataElementList = new ArrayList<>();
            for(DataElement data : dataList){
                DataElementDTO dataElement = new DataElementDTO();
                dataElement.setId(ComUtil.getId());
                dataElement.setName(data.getName());
                dataElement.setCnName(data.getCnName());
                dataElement.setCode(data.getCode());
                dataElement.setType(data.getType());
                dataElement.setLength(data.getLength());
                dataElement.setRemark(data.getRemark());
                dataElement.setTypeId(dataElementDTO.getTypeId());
                dataElement.setCreatedBy(userId);
                dataElement.setCreationDate(new Date());
                EntityUtils.setCreateAndUpdateInfo(dataElement);
                dataElementList.add(dataElement);
            }

            this.mapper.insertBatch(dataElementList);
            logger.info("导入数据元成功");
        }

        return errorList;
    }

    public List<DataElement> importParams(List<DataElement> paramList, String typeId) throws Exception {
        List<DataElement> errorList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(paramList)) {
            String userId = ThreadContextHelper.getUserId();
            if (StringUtils.isBlank(userId)) {
                userId = "1";
            }

            List<DataElementDTO> dataElementList = new ArrayList<>();
            for(DataElement param : paramList){
                // 检查参数名是否重名
                if(checkName(typeId, param.getName())){
                    errorList.add(param);
                }else{
                    DataElementDTO dataElement = new DataElementDTO();
                    dataElement.setId(ComUtil.getId());
                    dataElement.setName(param.getName()==null ? "" : param.getName());
                    dataElement.setCnName(param.getCnName()==null ? "" : param.getCnName());
                    dataElement.setType(param.getType()==null ? "" : param.getType());
                    dataElement.setLength(param.getLength()==null ? 0 : param.getLength());
                    dataElement.setRemark(param.getRemark()==null ? "" : param.getRemark());
                    dataElement.setTypeId(typeId);
                    dataElement.setCreatedBy(userId);
                    dataElement.setCreationDate(new Date());
                    EntityUtils.setCreateAndUpdateInfo(dataElement);
                    dataElementList.add(dataElement);
                }
            }

            if (CollectionUtils.isEmpty(errorList)) {
                this.mapper.insertBatch(dataElementList);
                logger.info("导入飞参参数到数据元成功");
            }else{
                logger.info("存在重名的参数,不能导入");
            }
        }
        return errorList;
    }

    /**
     * 检查参数重名
     * @param typeId
     * @param name
     * @return
     */
    private boolean checkName(String typeId, String name) {
        DataElementDTO dataElement = new DataElementDTO();
        dataElement.setTypeId(typeId);
        dataElement.setName(name);
        long num = this.selectCount(dataElement);

        if(num >= 1){
            return true;
        }else{
            return false;
        }
    }

    private String insertCommonType(String name) {
        CommonTypeDTO root = commonTypeService.selectRootByType(TYPE);

        CommonTypeDTO commonTypeQuery = new CommonTypeDTO();
        commonTypeQuery.setName(name);
        commonTypeQuery.setType(TYPE);
        commonTypeQuery.setParentId(root.getId());
        CommonTypeDTO commonTypeDTO = commonTypeService.selectOne(commonTypeQuery);
        if(commonTypeDTO != null){
            return commonTypeDTO.getId();
        }

        CommonTypeDTO commonType = new CommonTypeDTO();
        commonType.setId(ComUtil.getId());
        commonType.setName(name==null ? "" : name);
        commonType.setLeaf(1);
        commonType.setType(TYPE);
        commonType.setParentId(root.getId());
        commonType.setIcon("file");
        String userId = ThreadContextHelper.getUserId();
        if (StringUtils.isBlank(userId)) {
            userId = "1";
        }
        commonType.setCreatedBy(userId);
        commonType.setOrderBy(1);
        commonTypeService.insert(commonType);
        return commonType.getId();
    }

}
